package com.ruoyi.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSONArray;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ruoyi.domain.BaiduAIResponse;
import com.ruoyi.domain.Vo.AIRequestMessage;
import com.ruoyi.domain.WebSocketMessage;
import com.ruoyi.service.BaiduService;
import com.ruoyi.system.service.impl.SysConfigServiceImpl;
import com.ruoyi.utils.OKHttpUtils;
import com.ruoyi.utils.SimpleResult;
import com.ruoyi.websokcet.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class BaiduServiceImpl implements BaiduService {
    @Autowired
    private SysConfigServiceImpl sysConfigService;

    @Value("${baidu.ai.grantType}")
    private String default_grantType;

    @Value("${baidu.ai.clientId}")
    private String default_clientId;

    @Value("${baidu.ai.clientSecret}")
    private String default_clientSecret;

    @Value("${baidu.ai.model}")
    private String model;

    /**
     * 获取 ai接口[百度服务应用] 的token [使用自定义参数]
     * @return {@code Map<String, Object>}
     */
    @Override
    public Map<String, Object> getToken(String grantType, String clientId, String clientSecret) {
        Map<String, String> paramsForToken = new HashMap<>();
        if (grantType != null && clientId != null && clientSecret != null) {
            paramsForToken.put("grant_type", grantType);
            paramsForToken.put("client_id", clientId);
            paramsForToken.put("client_secret", clientSecret);
        } else {
            paramsForToken.put("grant_type", default_grantType);
            paramsForToken.put("client_id", default_clientId);
            paramsForToken.put("client_secret", default_clientSecret);
        }
        Map<String, Object> result = new HashMap<>(); // 结果集
        String params = mapToLinkParams(paramsForToken);
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/oauth/2.0/token" + params)
                .build();
        try (Response response = client.newCall(request).execute()){
            if (response.isSuccessful()) {
                String responseBody = response.body().string();
                final JSONObject jsonObject = JSONObject.parseObject(responseBody);
                result.put("baiduResponseCode", response.code());
                result.put("expiresIn", jsonObject.get("expires_in")); // token 有效时间 单位: 秒 有效期 30天
                result.put("error",  jsonObject.get("error")); // 错误码 响应失败时返回该字段，成功时不返回
                result.put("errorDescription", jsonObject.get("error_description")); // 错误描述信息，帮助理解和解决发生的错误
                result.put("accessToken", jsonObject.get("access_token")); // 得到的 token
            } else {
                result.put("baiduResponseCode", response.code());
                return result;
            }
        }catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return result;
    }

    /**
     * 获取accessToken[使用默认参数]
     * @return
     */
    @Override
    public Map<String, Object> getToken(){
        final Map<String, Object> result= getToken(null, null, null);
        return result;
    }

    /**
     * 语音识别 [语音转文字]
     * @return
     */
    @Override
    public Map<String, Object> speech(MultipartFile file) {
        Map<String, Object> result = new HashMap<>();

        String grantType = "client_credentials";
        String clientId = "WnDwApJQZ18xVyrtpfpzKC78";
        String clientSecret = "gJWhissX9VrOU1ImClF68A0uKFi31vcE";

        final Map<String, Object> tokenMap = getToken(grantType, clientId, clientSecret);
        final String accessToken = (String) tokenMap.get("accessToken");

        OkHttpClient httpClient = new OkHttpClient();

        String base64EncodedString = null; // base64编码
        byte[] fileContent = null; // 文件字节数组
        try {
            // 读取文件为字节数组
            fileContent = file.getBytes();
            // 将字节数组编码为Base64字符串
            base64EncodedString = Base64.getEncoder().encodeToString(fileContent);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 创建一个MediaType对象，设置请求体的内容类型为JSON
        MediaType JSON = MediaType.get("application/json; charset=utf-8");
        // 创建一个JSONObject或者任何你用来构建JSON的库的对象
        final JSONObject jsonObject = new JSONObject();
        jsonObject.put("format", "pcm"); // 语音的文件格式 pcm/wav/amr/m4a
        jsonObject.put("rate", "16000"); // 采样率, [16000, 8000] 固定值
        jsonObject.put("channel", "1"); // 声道数, 仅支持单声道, 固定值 1
        jsonObject.put("cuid", UUID.randomUUID().toString()); // 用户唯一标识, 自己生成, 建议使用mac地址
        jsonObject.put("token", accessToken); // 开放平台的 accessToken
        jsonObject.put("speech", base64EncodedString); // 本地文件的二级制数据, 需要进行base64编码, 配合len使用
        jsonObject.put("len", fileContent.length); // 本地语音的文件字节数
        // 将JSONObject转换为字符串
        String json = jsonObject.toString();
        // 创建RequestBody对象，将JSON字符串作为请求体
        RequestBody body = RequestBody.create(JSON, json);

        final Request request = new Request.Builder()
                .url("http://vop.baidu.com/server_api")
                .header("Content-Type", "application/json")
                .post(body)
                .build();

        // 获取响应
        try (Response response = httpClient.newCall(request).execute()){
            if (response.isSuccessful()) {
                String responseBody = response.body().string();
                final JSONObject resultJsonObject = JSONObject.parseObject(responseBody);
                result.put("result", resultJsonObject.getString("result"));
                result.put("errMsg", resultJsonObject.getString("err_msg"));
                result.put("sn", resultJsonObject.getString("sn"));
                result.put("corpusNo", resultJsonObject.getString("corpus_no"));
                result.put("errNo", resultJsonObject.getString("err_no"));
            } else {
                result.put("error", "服务器请求错误");
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 发送ai请求
     * @param requestMessage
     * @return
     */
    @Override
    public SimpleResult aiRequest(String requestMessage) {
        String aiSize = sysConfigService.selectConfigByKey("ai_size");
//        System.out.println("ai的值 =====>" + aiSize);
        // 解析成 baiduRequest 对象
        JSONArray messages = null;
        String uuid = "";
        try{
            com.alibaba.fastjson2.JSONObject jsonObject = com.alibaba.fastjson2.JSONObject.parseObject(requestMessage);
            uuid = jsonObject.getString("uuid");
            messages = jsonObject.getJSONArray("messages");
        } catch (Exception e) {
            e.printStackTrace();
            return SimpleResult.error("数据格式错误");
        }
//        System.out.println("开头: " + messages); // [{"role":"user","content":"你好"}]'
        Object o = messages.get(0);
        String objectJson = JSONObject.toJSONString(o);
        AIRequestMessage aiRequestMessage = JSONObject.parseObject(objectJson, AIRequestMessage.class);
//        System.out.println("解析出来的数据 ==》 " + aiRequestMessage);
        log.error(uuid + " 问题 ======> " + aiRequestMessage.getContent());
        aiRequestMessage.setContent(aiRequestMessage.getContent() + ",请用" + aiSize + "个字回答");
        messages.fluentRemove(0);
        JSONObject jo = JSONObject.parseObject(JSONObject.toJSONString(aiRequestMessage));
        messages.fluentAdd(jo);
//        System.out.println("最终的messages ====> " + messages);

        StringBuilder output = new StringBuilder();
        Map<String, Object> bodyMap = new ConcurrentSkipListMap<>();
        bodyMap.put("messages", messages);
        bodyMap.put("stream", true);
        String jsonString = com.alibaba.fastjson2.JSONObject.toJSONString(bodyMap);
//        System.out.println("组装: " + jsonString);

        okhttp3.RequestBody body = okhttp3.RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonString);

        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/" + model + "?access_" +
                        "token=" + getToken().get("accessToken"))
                .header("Content-Type", "application/json") // 设置Content-Type头
                .post(body)
                .build();

        try (Response response = OKHttpUtils.client().newCall(request).execute()) {
            if (!response.isSuccessful()) {
                log.error("请求百度AI接口错误~");
                return SimpleResult.error("请求百度AI接口错误~");
//                throw new IOException("Unexpected code " + response);
            } else {
                // 获取响应体的输入流
                InputStream inputStream = response.body().byteStream();

                // 创建一个缓冲区来读取数据
                byte[] buffer = new byte[1024]; // 你可以根据需要调整缓冲区的大小
                int bytesRead;

                String lastData = "";  // 数据末尾不完整的数据
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    // 读取数据直到输入流结束
                    String dataChunk = new String(buffer, 0, bytesRead, "UTF-8");
                    // 得到数据之前先把上一次不完整的数据添加进来
                    dataChunk = (lastData.equals("")?"":"data: ") + lastData + dataChunk;
                    lastData = "";
//                    log.error(uuid + " 百度ai原始返回 ======> " + dataChunk);
                    // 这里可以处理每一块数据，比如写入文件或进行其他操作
                    String dataSources = "";
                    Thread.sleep(200);
                    if(dataChunk.length() > 6) {
                        dataSources = dataChunk.substring(6);
                    } else {
                        continue;
                    }
//                    String dataSources = dataChunk.substring(6);
                    String[] dataList = dataSources.split("data: ");
                    for (String data : dataList) {
//                        log.error(uuid + " 回答 ======> " + data);
                        if (dataIsValid(data)) {
                            final BaiduAIResponse baiduAIResponse = new BaiduAIResponse(data);
                            final WebSocketServer webSocketServer = WebSocketServer.getServer(uuid);

                            final WebSocketMessage<BaiduAIResponse> webSocketMessage
                                    = new WebSocketMessage<>("3", uuid, baiduAIResponse);
                            if(Objects.isNull(webSocketServer)) {
                                log.error("请检查websocket的连接状态~");
                                return SimpleResult.error("请检查websocket的连接状态~");
                            }
                            webSocketServer.sendMessage(JSONObject.toJSONString(webSocketMessage));
                        }else {
                            lastData = data; // 如果数据不完整就记录下来
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            return SimpleResult.error("服务器太火爆了, 请稍后再试试吧~");
        }
        return SimpleResult.success("OK!");
    }

    //    无流式
    @Override
    public SimpleResult aiRequestDevices(String requestMessage) {
        System.out.println(requestMessage);
        // 解析成 baiduRequest 对象
        com.alibaba.fastjson2.JSONObject jsonObject = com.alibaba.fastjson2.JSONObject.parseObject(requestMessage);
        String uuid = jsonObject.getString("uuid");
        JSONArray messages = jsonObject.getJSONArray("messages");
        System.out.println("开头: " + messages); // [{"role":"user","content":"你好"}]'
        Object o = messages.get(0);
        String objectJson = JSONObject.toJSONString(o);
        AIRequestMessage aiRequestMessage = JSONObject.parseObject(objectJson, AIRequestMessage.class);
        System.out.println("解析出来的数据 ==》 " + aiRequestMessage);
        log.error(uuid + " 问题 ======> " + aiRequestMessage.getContent());
        aiRequestMessage.setContent(aiRequestMessage.getContent() + ",请用50个字回答");
        messages.fluentRemove(0);
        JSONObject jo = JSONObject.parseObject(JSONObject.toJSONString(aiRequestMessage));
        messages.fluentAdd(jo);
        System.out.println("最终的messages ====> " + messages);

        StringBuilder output = new StringBuilder();
        Map<String, Object> bodyMap = new ConcurrentSkipListMap<>();
        bodyMap.put("messages", messages);
        String jsonString = com.alibaba.fastjson2.JSONObject.toJSONString(bodyMap);
//        System.out.println("组装: " + jsonString);

        okhttp3.RequestBody body = okhttp3.RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonString);

        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/" + model + "?access_" +
                        "token=" + getToken().get("accessToken"))
                .header("Content-Type", "application/json") // 设置Content-Type头
                .post(body)
                .build();
        try (Response response = OKHttpUtils.client().newCall(request).execute()) {
            if (!response.isSuccessful()) {
                log.error("请求百度AI接口错误~");
                return SimpleResult.error("请求百度AI接口错误~");
//                throw new IOException("Unexpected code " + response);
            } else {
                System.out.println(response.toString());
                return SimpleResult.success(response.toString());
                // 获取响应体的输入流
//                InputStream inputStream = response.body().byteStream();
//
//                // 创建一个缓冲区来读取数据
//                byte[] buffer = new byte[1024]; // 你可以根据需要调整缓冲区的大小
//                int bytesRead;
//
//                while ((bytesRead = inputStream.read(buffer)) != -1) {
//                    // 读取数据直到输入流结束
//                    String dataChunk = new String(buffer, 0, bytesRead, "UTF-8");
//                    log.error(uuid + " 百度ai原始返回 ======> " + dataChunk);
//                    // 这里可以处理每一块数据，比如写入文件或进行其他操作
//                    String dataSources = "";
//                    if(dataChunk.length() > 6) {
//                        dataSources = dataChunk.substring(6);
//                    } else {
//                        continue;
//                    }
////                    String dataSources = dataChunk.substring(6);
//                    String[] dataList = dataSources.split("data: ");
//                    for (String data : dataList) {
//                        log.error(uuid + " 回答 ======> " + data);
//                        final BaiduAIResponse baiduAIResponse = new BaiduAIResponse(data);
//                        final WebSocketServer webSocketServer = WebSocketServer.getServer(uuid);
//
//                        final WebSocketMessage<BaiduAIResponse> webSocketMessage
//                                = new WebSocketMessage<>("3", uuid, baiduAIResponse);
//                        if(Objects.isNull(webSocketServer)) {
//                            log.error("请检查websocket的连接状态~");
//                            return SimpleResult.error("请检查websocket的连接状态~");
//                        }
//                        webSocketServer.sendMessage(com.alibaba.fastjson2.JSONObject.toJSONString(webSocketMessage));
//                    }
//                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            return SimpleResult.error("服务器太火爆了, 请稍后再试试吧~");
        }
    }

    /**
     * 判断数据的完整性
     */
    public boolean dataIsValid(String data) {
        try {
            if (data.startsWith("data")){
                data = data.replace("data: ", "");
            }
            JSONObject jsonObject = JSONObject.parseObject(data);
            return true;
        }catch (Exception e) {
            return false;
        }
    }

    /**
     * 传递一个map, 解析成请求的参数(?param1=param1&param2=param2)格式
     * @param params
     * @return {@code String}
     */
    public static String mapToLinkParams(Map<String, String> params) {
        StringBuilder sb = new StringBuilder("?");
        Set<String> keySet = params.keySet();
        int currentParamNums = 0; // 当前是第几个参数
        for (String key : keySet) {
            currentParamNums++;
            if (currentParamNums != keySet.size()) {
                sb.append(key + "=" + params.get(key) + "&");
            } else {
                sb.append(key + "=" + params.get(key));
            }
        }
        return sb.toString();
    }
}
